import ReconnectingWebSocket from 'reconnecting-websocket';
import pako from 'pako'
/**
 * WebSocket 管理器
 * @param {string} url WebSocket 地址
 * @param {object} options 配置选项
 * @param {number} [options.reconnectInterval=3000] 重连间隔 (ms)
 * @param {number} [options.heartbeatInterval=15000] 心跳间隔 (ms)
 * @param {string} [options.heartbeatMessage='ping'] 心跳消息
 */
export default class WebSocketManager {
  constructor(url, options = {}) {
    // 配置参数
    this.url = url;
    this.reconnectInterval = options.reconnectInterval || 3000;
    this.heartbeatInterval = options.heartbeatInterval || 15000;
    this.heartbeatMessage = options.heartbeatMessage || 'ping';

    // 内部状态
    this.socket = null;
    this.heartbeatTimer = null;
    this.messageQueue = []; // 消息队列（连接未就绪时缓存消息）
    this.isDestroyed = false;

    // 事件监听器
    this.listeners = {
      // open: null,
      // message: null,
      // error: null,
      // close: null,
    };

    // 初始化连接
    this.connect();
  }

  // 建立 WebSocket 连接
  connect() {
    if (this.isDestroyed) return;

    this.socket = new ReconnectingWebSocket(this.url, [], {
      connectionTimeout: 5000,
      maxRetries: Infinity,
      minReconnectionDelay: this.reconnectInterval,
    });

    // 绑定事件
    this.socket.onopen = (event) => {
      console.log('WebSocket 已连接');
      this.startHeartbeat();
      this.flushMessageQueue(); // 发送缓存的消息
      this.emit('open', event);
    };

    this.socket.onmessage = async (event) => {
		const buffer = await event.data.arrayBuffer();
		let ploydata = new Uint8Array(buffer);
		let msg = pako.inflate(ploydata, {to: 'string'});
		let result = JSON.parse(msg);
		if(result.pong){
			return;
		}
		//console.log("onmessage: ", result)
		if(result && result.rep){
			result.data = JSON.parse(result.data);
			//console.log("收到服务器rep内容：", result)
			this.emit(`req-${result.rep}`, {data: result})
		}
		if(result && result.ch){
			//console.log("收到服务器sub内容：", result)
			this.emit(`sub-${result.ch}`,{data: result})
		}
    };

    this.socket.onerror = (error) => {
      console.error('WebSocket 错误:', error);
      this.emit('error', error);
    };

    this.socket.onclose = (event) => {
      console.log('WebSocket 已关闭');
      this.stopHeartbeat();
      this.emit('close', event);
    };
  }

  // 发送心跳包
  startHeartbeat() {
    this.stopHeartbeat();
    this.heartbeatTimer = setInterval(() => {
      if (this.isConnected()) {
        this.sendRaw(JSON.stringify({"ping": new Date().getTime()}));
      }
    }, this.heartbeatInterval);
  }

  // 停止心跳
  stopHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
  }

  // 发送消息（自动缓存未连接时的消息）
  send(data) {
    if (this.isConnected()) {
      this.sendRaw(data);
    } else {
      this.messageQueue.push(data); // 加入队列
    }
  }

  // 直接发送原始消息
  sendRaw(data) {
    this.socket.send(data);
  }

  // 发送队列中的缓存消息
  flushMessageQueue() {
    while (this.messageQueue.length > 0 && this.isConnected()) {
      this.sendRaw(this.messageQueue.shift());
    }
  }

  // 检查连接状态
  isConnected() {
    return this.socket && this.socket.readyState === WebSocket.OPEN;
  }

  // 销毁实例（关闭连接并清理资源）
  destroy() {
    this.isDestroyed = true;
    this.stopHeartbeat();
    if (this.socket) {
      this.socket.close();
    }
	this.listeners = {};
    // this.listeners.open.clear();
    // this.listeners.message.clear();
    // this.listeners.error.clear();
    // this.listeners.close.clear();
  }

  // 事件监听
  on(event, callback) {
    if (!this.listeners[event]) {
	  //console.log("on: ", event, '   ',this.listeners[event])
      //this.listeners[event].add(callback);
	  this.listeners[event] = callback;
    }
    return this; // 支持链式调用
  }

  // 移除监听
  off(event, callback) {
    if (this.listeners[event]) {
      this.listeners[event].delete(callback);
    }
    return this;
  }

  // 触发事件
  emit(event, ...args) {
	  //console.log("emit: ", event, '    ',this.listeners[event])
    if (this.listeners[event]) {
		this.listeners[event](...args);
      //this.listeners[event].forEach((callback) => callback(...args));
    }
  }
}